package com.flycms.esmodule.service;

import com.flycms.esmodule.constant.EsConstant;
import com.flycms.esmodule.dao.EsSoftDao;
import com.flycms.esmodule.model.EsSoft;
import com.flycms.esmodule.model.EsSoft;
import com.flycms.esmodule.utils.EsUtils;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * @author huangzt
 * @version 1.0
 * @date 2020/3/15 19:32
 */
@Service
public class EsSoftService {
    
    @Autowired
    EsSoftDao esSoftDao;

    @Autowired
    ElasticsearchTemplate elasticsearchTemplate;

    public Page<EsSoft> getEsSoftByKeys(String keyword, Pageable pageable) {
        Sort sort = Sort.by(Sort.Direction.DESC,"read_size","comment_size","like_size");
        if (pageable.getSort() == null) {
            pageable = PageRequest.of(pageable.getPageNumber()-1, pageable.getPageSize(), sort);
        }
        if(keyword==null || "".equals(keyword)){
            return esSoftDao.findAll(pageable);
        }
        //keyword 含有空格时抛异常
        //return esBlogRepository.findDistinctEsBlogByTitleContainingOrSummaryContainingOrContentContainingOrTagsContaining(keyword, keyword, keyword, keyword, pageable);

        //使用 Elasticsearch API QueryBuilder
        NativeSearchQueryBuilder aNativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        // 组合查询，boost即为权重，数值越大，权重越大
        QueryBuilder queryBuilder = QueryBuilders.boolQuery()
                .should(QueryBuilders.multiMatchQuery(keyword, "softName").boost(4))
                .should(QueryBuilders.multiMatchQuery(keyword,  "softPlatform").boost(2))
                .should(QueryBuilders.multiMatchQuery(keyword, "softDescription").boost(3))
                .should(QueryBuilders.multiMatchQuery(keyword, "softVersion").boost(1));
        // 高亮设置
        List<String> highlightFields = new ArrayList<>();
        highlightFields.add("softName");
        highlightFields.add("softPlatform");
        highlightFields.add("softDescription");
        highlightFields.add("softVersion");
        HighlightBuilder.Field[] fields = new HighlightBuilder.Field[highlightFields.size()];
        for (int x = 0; x < highlightFields.size(); x++) {
            fields[x] = new HighlightBuilder.Field(highlightFields.get(x)).preTags(EsConstant.HIGH_LIGHT_START_TAG)
                    .postTags(EsConstant.HIGH_LIGHT_END_TAG);
        }

        aNativeSearchQueryBuilder.withIndices(EsConstant.INDEX_NAME.SOFT).withTypes(EsConstant.INDEX_NAME.TYPE)
                .withQuery(queryBuilder)
                .withHighlightFields(fields).withPageable(pageable);
        NativeSearchQuery build = aNativeSearchQueryBuilder.build();
        Page<EsSoft> plist = elasticsearchTemplate.queryForPage(build, EsSoft.class, new SearchResultMapper() {
            @Override
            public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> aClass, Pageable pageable) {
                // 获取高亮搜索数据
                List<EsSoft> list = new ArrayList<>();
                SearchHits hits = response.getHits();
                for (SearchHit searchHit : hits) {
                    if (hits.getHits().length <= 0) {
                        return null;
                    }
                    EsSoft data = new EsSoft();
                    // 公共字段
                    data.setId((int)searchHit.getSourceAsMap().get("id"));
                    data.setSoftName(String.valueOf(searchHit.getSourceAsMap().get("softName")));
                    data.setSoftPlatform(String.valueOf(searchHit.getSourceAsMap().get("softPlatform")));
                    data.setSoftDescription(String.valueOf(searchHit.getSourceAsMap().get("softDescription")));
                    data.setSoftVersion(String.valueOf(searchHit.getSourceAsMap().get("softVersion")));
                    Object createTime = searchHit.getSourceAsMap().get("createTime");
                    Object updateTime = searchHit.getSourceAsMap().get("updateTime");
                    if (createTime != null) {
                        data.setCreateTime(EsUtils.formateDate(String.valueOf(createTime)));
                    }
                    if (updateTime != null) {
                        data.setUpdateTime(EsUtils.formateDate(String.valueOf(updateTime)));
                    }
                    // 反射调用set方法将高亮内容设置进去
                    try {
                        for (String field : highlightFields) {
                            HighlightField highlightField = searchHit.getHighlightFields().get(field);
                            if (highlightField != null) {
                                EsUtils.setHighLight(searchHit,field,data);
                            }
                        }

                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    list.add(data);
                }

                if (list.size() > 0) {
                    AggregatedPage<T> result = new AggregatedPageImpl<>((List<T>) list, pageable,
                            response.getHits().getTotalHits());
                    return result;
                }
                return null;
            }

            @Override
            public <T> T mapSearchHit(SearchHit searchHit, Class<T> aClass) {
                return null;
            }
        });
        return  plist;
    }
    
}
